<script setup>
import { ref, reactive, onMounted } from 'vue'
import { Edit, Delete } from '@element-plus/icons-vue'
import { listUsers, addUser, removeUsers, getUserById, STATUS_LABEL_BY_CODE } from '@/services/userApi'
import { listDepts } from '@/services/departmentApi'
import { listRoles } from '@/services/roleApi'
import http from '@/services/http'

// 搜索与分页
const query = reactive({ name: '', phone: '', deptId: '', roleId: '', status: '' })
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const loading = ref(false)

// 数据
const list = ref([])
const depts = ref([])
const roles = ref([])

// 选择与批量删除
const selectedIds = ref([])
let deleteMode = 'single' // single | batch
let currentId = 0

// 弹窗与表单
const showAdd = ref(false)
const showEdit = ref(false)
const showDelete = ref(false)
const form = reactive({
  id: null,
  username: '',
  name: '',
  phone: '',
  email: '',
  gender: 1,
  status: 1,
  deptId: '',
  roleId: '',
  image: '',
  remark: '',
})

// 轻量提示
const toast = reactive({ show: false, text: '', type: 'info' })
function tip(text, type='info'){ toast.text=text; toast.type=type; toast.show=true; setTimeout(()=>toast.show=false, 1800) }

function maskPhone(p){ if(!p) return ''; return p.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }

// 头像上传：预览 + 上传
const avatarPreview = ref('')
const avatarFile = ref(null)
const uploading = ref(false)
const fileInputRef = ref(null)

function openFilePicker(){ fileInputRef.value?.click() }
function onAvatarChange(e){
  const f = e.target.files?.[0]
  if(!f) return
  const types = ['image/png','image/jpeg','image/jpg']
  if(!types.includes(f.type)){ tip('仅支持 png/jpg/jpeg','error'); e.target.value=''; return }
  if(f.size > 2 * 1024 * 1024){ tip('图片不能超过2M','error'); e.target.value=''; return }
  avatarFile.value = f
  avatarPreview.value = URL.createObjectURL(f)
  uploadAvatar(f)
}
async function uploadAvatar(file){
  uploading.value = true
  try{
    // 按你的后端规范：POST /upload，multipart/form-data，参数名为 image（file 类型）
    const fd = new FormData(); fd.append('image', file)
    const raw = await http.post('/upload', fd, { headers: { 'Content-Type': 'multipart/form-data' } })
    // 尝试从返回结果中提取图片地址（兼容多种后端字段命名）
    function pickUrl(obj){
      if(!obj) return undefined
      if(typeof obj === 'string') return obj
      const keys = ['url','fileUrl','imageUrl','image','avatar','path','location','link','src']
      for(const k of keys){ if(typeof obj[k] === 'string' && obj[k]) return obj[k] }
      // 常见的嵌套结构 data、result
      if(obj.data){ const u = pickUrl(obj.data); if(u) return u }
      if(obj.result){ const u = pickUrl(obj.result); if(u) return u }
      // 数组: 取第一个元素的 url
      if(Array.isArray(obj.urls) && obj.urls.length>0){ const u = pickUrl(obj.urls[0]); if(u) return u }
      if(Array.isArray(obj.files) && obj.files.length>0){ const u = pickUrl(obj.files[0]); if(u) return u }
      if(Array.isArray(obj.list) && obj.list.length>0){ const u = pickUrl(obj.list[0]); if(u) return u }
      return undefined
    }
    const url = pickUrl(raw)
    if(url){ form.image = url; tip('头像上传成功','success') } else { console.warn('上传返回值', raw); tip('头像上传成功，但未返回URL，请检查后端返回结构','info') }
  }catch(e){ tip('头像上传失败','error') } finally { uploading.value = false }
}
function removeAvatar(){ avatarFile.value=null; avatarPreview.value=''; form.image='' }

async function fetchDicts(){
  const [deptRes, roleRes] = await Promise.all([ listDepts({ page:1, pageSize:1000 }), listRoles({ page:1, pageSize:1000 }) ])
  // 修复：departmentApi / roleApi 返回 { list, total }
  depts.value = deptRes.list || []
  roles.value = roleRes.list || []
}

async function fetchList(){
  loading.value = true
  try{
    const { rows, total: t } = await listUsers({
      name: query.name,
      phone: query.phone,
      deptId: query.deptId || undefined,
      roleId: query.roleId || undefined,
      status: query.status || undefined,
      page: page.value,
      pageSize: pageSize.value,
    })
    list.value = rows
    total.value = t
  } finally {
    loading.value = false
  }
}

function search(){ page.value = 1; fetchList() }
function clear(){ Object.assign(query, { name:'', phone:'', deptId:'', roleId:'', status:'' }); page.value=1; fetchList() }

function toggleAll(e){ if(e.target.checked){ selectedIds.value = list.value.map(u=>u.id) } else { selectedIds.value = [] } }
function toggleOne(id, e){ const checked=e.target.checked; const i=selectedIds.value.indexOf(id); if(checked && i<0){ selectedIds.value.push(id) } else if(!checked && i>=0){ selectedIds.value.splice(i,1) } }

function openAdd(){ Object.assign(form, { id:null, username:'', name:'', phone:'', email:'', gender:1, status:1, deptId:'', roleId:'', image:'', remark:'' }); avatarPreview.value=''; avatarFile.value=null; showAdd.value=true }
async function confirmAdd(){
  try{
    if(uploading.value){ tip('头像正在上传，请稍后保存','info'); return }
    // 如果已选择文件但未得到后端URL，尝试补发上传
    if(avatarFile.value && !form.image){ await uploadAvatar(avatarFile.value) }
    // 后端要求 image 填充为上传后的地址
    if(!form.image || typeof form.image !== 'string'){ tip('请先上传头像图片','error'); return }
    await addUser({
      username: form.username,
      name: form.name,
      phone: form.phone,
      email: form.email,
      gender: form.gender,
      status: form.status,
      deptId: form.deptId || null,
      roleId: form.roleId || null,
      image: form.image, // 关键：将地址值填充到 image 参数
      remark: form.remark || null,
    })
    tip('添加成功','success'); showAdd.value=false; fetchList()
  }catch(e){ tip('添加失败','error') }
}

async function openEdit(row){ const data = await getUserById(row.id); Object.assign(form, data||{}); showEdit.value=true }
function confirmEdit(){ tip('暂未对接修改接口','info') }

function openDelete(row){ deleteMode='single'; currentId=row.id; showDelete.value=true }
function openBatchDelete(){ if(selectedIds.value.length===0){ return tip('请先选择要删除的用户','info') } deleteMode='batch'; showDelete.value=true }

async function confirmDelete(){
  const idsCsv = deleteMode==='batch' ? selectedIds.value.join(',') : String(currentId)
  try{ await removeUsers(idsCsv); tip('删除成功','success'); showDelete.value=false; fetchList(); selectedIds.value=[] }catch(e){ tip('删除失败','error') }
}

function prev(){ if(page.value>1){ page.value--; fetchList() } }
function next(){ const last = Math.ceil(total.value/pageSize.value)||1; if(page.value<last){ page.value++; fetchList() } }

onMounted(async()=>{ await fetchDicts(); await fetchList() })
</script>

<template>
  <div class="container">
    <!-- 工具栏 -->
    <div class="toolbar">
      <div class="filter-row">
        <div class="field"><span class="label">姓名</span><input v-model="query.name" placeholder="请输入姓名" /></div>
        <div class="field"><span class="label">手机号</span><input v-model="query.phone" placeholder="请输入手机号" /></div>
        <div class="field"><span class="label">部门</span>
          <select v-model="query.deptId"><option value="">请选择</option><option v-for="d in depts" :key="d.id" :value="d.id">{{ d.name }}</option></select>
        </div>
        <div class="field"><span class="label">角色</span>
          <select v-model="query.roleId"><option value="">请选择</option><option v-for="r in roles" :key="r.id" :value="r.id">{{ r.name }}</option></select>
        </div>
        <div class="field"><span class="label">状态</span>
          <select v-model="query.status"><option value="">请选择</option><option value="1">正常</option><option value="0">停用</option></select>
        </div>
        <div class="actions">
          <button class="btn" @click="search"><span class="icon">🔍</span>搜索</button>
          <button class="btn btn-secondary" @click="clear"><span class="icon">♻️</span>重置</button>
        </div>
      </div>
      <div class="toolbar-divider"></div>
      <div class="action-row">
        <el-button type="primary" @click="openAdd"><el-icon><Edit/></el-icon>添加用户</el-button>
        <el-button type="danger" @click="openBatchDelete"><el-icon><Delete/></el-icon>批量删除</el-button>
      </div>
    </div>

    <!-- 列表 -->
    <div class="table-card">
      <table>
        <thead>
          <tr>
            <th style="width:40px"><input type="checkbox" :checked="selectedIds.length===list.length && list.length>0" @change="toggleAll" /></th>
            <th>姓名</th>
            <th>用户名</th>
            <th>头像</th>
            <th>部门</th>
            <th>角色</th>
            <th>手机号</th>
            <th>状态</th>
            <th>最后修改时间</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-if="loading"><td colspan="10" class="loading">加载中...</td></tr>
          <tr v-for="u in list" :key="u.id">
            <td><input type="checkbox" :checked="selectedIds.includes(u.id)" @change="e=>toggleOne(u.id,e)" /></td>
            <td>{{ u.name }}</td>
            <td>{{ u.username }}</td>
            <td>
              <el-avatar v-if="u.image" :src="u.image" size="small" />
              <div v-else class="avatar-placeholder"></div>
            </td>
            <td>{{ u.deptName }}</td>
            <td>{{ u.roleName }}</td>
            <td>{{ maskPhone(u.phone) }}</td>
            <td>
              <span class="badge" :class="u.status===1?'ok':'off'">{{ STATUS_LABEL_BY_CODE[u.status] }}</span>
            </td>
            <td>{{ u.updateTime }}</td>
            <td>
              <el-button size="small" type="primary" @click="openEdit(u)"><el-icon><Edit/></el-icon>修改</el-button>
              <el-button size="small" type="danger" @click="openDelete(u)"><el-icon><Delete/></el-icon>删除</el-button>
            </td>
          </tr>
          <tr v-if="!loading && list.length===0"><td colspan="10" class="empty">暂无数据</td></tr>
        </tbody>
      </table>
    </div>

    <!-- 分页 -->
    <div class="pagination">
      <div class="left">共 {{ total }} 条</div>
      <div class="pages">
        <button class="page" :disabled="page===1" @click="prev">上一页</button>
        <span class="page active">{{ page }}</span>
        <button class="page" @click="next">下一页</button>
      </div>
      <div class="right">
        <select v-model.number="pageSize" @change="fetchList"><option :value="10">10条/页</option><option :value="20">20条/页</option><option :value="30">30条/页</option></select>
      </div>
    </div>

    <!-- 添加用户弹窗 -->
    <div v-if="showAdd" class="modal">
      <div class="dialog">
        <div class="dialog-header">添加用户</div>
        <div class="dialog-body">
          <div class="form-grid">
            <label>用户名</label><input v-model="form.username" placeholder="唯一用户名" />
            <label>姓名</label><input v-model="form.name" placeholder="请输入姓名" />
            <label>手机号</label><input v-model="form.phone" placeholder="请输入手机号" />
            <label>邮箱</label><input v-model="form.email" placeholder="请输入邮箱" />
            <label>性别</label>
            <select v-model.number="form.gender"><option :value="1">男</option><option :value="2">女</option></select>
            <label>状态</label>
            <select v-model.number="form.status"><option :value="1">正常</option><option :value="0">停用</option></select>
            <label>部门</label>
            <select v-model="form.deptId"><option value="">请选择</option><option v-for="d in depts" :key="d.id" :value="d.id">{{ d.name }}</option></select>
            <label>角色</label>
            <select v-model="form.roleId"><option value="">请选择</option><option v-for="r in roles" :key="r.id" :value="r.id">{{ r.name }}</option></select>
            <label>头像</label>
            <div class="avatar-upload">
              <div class="avatar-box" :class="{ uploading }" @click="openFilePicker">
                <img v-if="avatarPreview || form.image" :src="avatarPreview || form.image" alt="avatar" />
                <div v-else class="plus">+</div>
                <input ref="fileInputRef" type="file" accept=".png,.jpg,.jpeg" @change="onAvatarChange" style="display:none" />
              </div>
              <div class="avatar-hint">图片上传，支持扩展名：.png / .jpg / .jpeg<br/>大小限制： 2M</div>
            </div>
            <label>备注</label><textarea v-model="form.remark" rows="3" placeholder="50字以内"></textarea>
          </div>
        </div>
        <div class="dialog-footer"><button class="btn btn-secondary" @click="showAdd=false">取消</button><el-button type="primary" :disabled="uploading" @click="confirmAdd">确定</el-button></div>
      </div>
    </div>

    <!-- 修改用户弹窗（仅展示，不保存） -->
    <div v-if="showEdit" class="modal">
      <div class="dialog">
        <div class="dialog-header">修改用户</div>
        <div class="dialog-body">
          <div class="form-grid">
            <label>用户名</label><input v-model="form.username" />
            <label>姓名</label><input v-model="form.name" />
            <label>手机号</label><input v-model="form.phone" />
            <label>邮箱</label><input v-model="form.email" />
            <label>性别</label><select v-model.number="form.gender"><option :value="1">男</option><option :value="2">女</option></select>
            <label>状态</label><select v-model.number="form.status"><option :value="1">正常</option><option :value="0">停用</option></select>
            <label>部门</label><select v-model="form.deptId"><option value="">请选择</option><option v-for="d in depts" :key="d.id" :value="d.id">{{ d.name }}</option></select>
            <label>角色</label><select v-model="form.roleId"><option value="">请选择</option><option v-for="r in roles" :key="r.id" :value="r.id">{{ r.name }}</option></select>
            <label>头像</label>
            <div class="avatar-upload">
              <div class="avatar-box" :class="{ uploading }" @click="openFilePicker">
                <img v-if="avatarPreview || form.image" :src="avatarPreview || form.image" alt="avatar" />
                <div v-else class="plus">+</div>
                <input ref="fileInputRef" type="file" accept=".png,.jpg,.jpeg" @change="onAvatarChange" style="display:none" />
              </div>
              <div class="avatar-hint">图片上传，支持扩展名：.png / .jpg / .jpeg<br/>大小限制： 2M</div>
            </div>
            <label>备注</label><textarea v-model="form.remark" rows="3"></textarea>
          </div>
          <div class="tip">提示：编辑展示已对接，保存接口暂未提供。</div>
        </div>
        <div class="dialog-footer"><button class="btn btn-secondary" @click="showEdit=false">关闭</button><el-button disabled @click="confirmEdit">保存</el-button></div>
      </div>
    </div>

    <!-- 删除确认弹窗 -->
    <div v-if="showDelete" class="modal">
      <div class="dialog small">
        <div class="dialog-header">确认删除</div>
        <div class="dialog-body">{{ deleteMode==='batch' ? '是否删除选中的用户？此操作不可恢复。' : `是否删除用户“${form.name}”？此操作不可恢复。` }}</div>
        <div class="dialog-footer"><button class="btn btn-secondary" @click="showDelete=false">取消</button><el-button type="danger" @click="confirmDelete"><el-icon><Delete/></el-icon>删除</el-button></div>
      </div>
    </div>

    <!-- 轻量提示 -->
    <div v-if="toast.show" class="toast" :class="toast.type">{{ toast.text }}</div>
  </div>
</template>

<style scoped>
.container{ width:100%; padding:0 16px 16px; position:relative; }
.toolbar{ display:flex; flex-direction:column; gap:12px; }
.filter-row{ display:flex; align-items:center; gap:12px; flex-wrap:nowrap; }
.action-row{ display:flex; align-items:center; gap:10px; }
.field{ display:flex; align-items:center; gap:8px; }
.label{ color:#374151; }
.actions{ margin-left:auto; display:flex; gap:10px; }
.table-card{ margin-top:14px; background:#fff; border:1px solid #e5e7eb; border-radius:12px; box-shadow:0 6px 16px rgba(0,0,0,0.06); overflow-x:auto; min-height:520px; }
.table-card table{ width:100%; border-collapse:collapse; }
.table-card th,.table-card td{ border:1px solid #e5e7eb; line-height:52px; text-align:center; }
.table-card th{ background:#f7f7f8; color:#374151; font-weight:600; }
.table-card .loading,.table-card .empty{ color:#6b7280; height:60px; }
.avatar-placeholder{ width:32px; height:32px; border-radius:50%; background:#e5e7eb; display:inline-block; }
.badge{ display:inline-block; padding:2px 10px; border-radius:999px; border:1px solid #e5e7eb; font-size:12px; }
.badge.ok{ background:#e6fffb; border-color:#b5f5ec; color:#16a34a; }
.badge.off{ background:#fff1f0; border-color:#ffccc7; color:#9ca3af; }
.pagination{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:14px; }
.pagination .left{ color:#666; }
.pagination .pages{ display:flex; gap:6px; }
.page{ padding:4px 10px; border:1px solid #e5e7eb; border-radius:6px; background:#fff; cursor:pointer; }
.page.active{ background:#08dcf3; border-color:#08dcf3; color:#0f172a; }
.page:disabled{ opacity:.5; cursor:not-allowed; }
.pagination .right select{ padding:6px 8px; border:1px solid #d1d5db; border-radius:6px; }
input,select,textarea{ padding:8px 10px; border:1px solid #d1d5db; border-radius:6px; background:#fff; min-width:160px; }
.btn{ background:#08dcf3; color:#0f172a; padding:8px 20px; border-radius:8px; border:1px solid #08dcf3; cursor:pointer; }
.btn:hover{ opacity:.9; }
.btn-primary{ background:#1677ff; border-color:#1677ff; color:#fff; }
.btn-secondary{ background:#fff; border-color:#cbd5e1; color:#0f172a; }
.btn.danger{ background:#ff4d4f; border-color:#ff4d4f; color:#fff; }
.modal{ position:fixed; inset:0; background:rgba(0,0,0,.35); display:grid; place-items:center; z-index:1000; }
.dialog{ background:#fff; border-radius:12px; width:720px; max-width:calc(100% - 48px); box-shadow:0 10px 24px rgba(0,0,0,.15); }
.dialog.small{ width:420px; }
.dialog-header{ padding:14px 18px; font-weight:600; border-bottom:1px solid #eee; }
.dialog-body{ padding:16px 18px; color:#333; }
.dialog-footer{ padding:12px 18px; display:flex; justify-content:flex-end; gap:10px; border-top:1px solid #eee; }
.form-grid{ display:grid; grid-template-columns:120px 1fr; gap:12px; align-items:center; }
.form-grid textarea{ grid-column:1/-1; }
.toast{ position:fixed; top:18px; left:50%; transform:translateX(-50%); padding:10px 14px; border-radius:8px; color:#0f172a; box-shadow:0 8px 20px rgba(0,0,0,.12); z-index:2000; background:#fff; border:1px solid #e5e7eb; }
.toast.success{ background:#e6fffb; border-color:#b5f5ec; }
.toast.error{ background:#fff1f0; border-color:#ffccc7; }
.toast.info{ background:#f0f9ff; border-color:#bae6fd; }
.tip{ margin-top:8px; color:#6b7280; }
.toolbar-divider{ height:1px; background:#e5e7eb; }
</style>

<style scoped>
.avatar-upload{ display:flex; align-items:center; gap:16px; }
.avatar-box{ width:160px; height:160px; border:1px dashed #cbd5e1; border-radius:12px; display:flex; align-items:center; justify-content:center; background:#fafafa; cursor:pointer; position:relative; }
.avatar-box .plus{ font-size:42px; color:#9ca3af; line-height:1; }
.avatar-box img{ width:100%; height:100%; object-fit:cover; border-radius:12px; }
.avatar-hint{ color:#6b7280; }
.avatar-box.uploading::after{ content:'上传中...'; position:absolute; inset:0; background:rgba(255,255,255,.7); display:flex; align-items:center; justify-content:center; color:#374151; font-size:14px; border-radius:12px; }
</style>